package socks.server;

import socks.ProxyMessage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
This class implements SOCKS5 User/Password authentication scheme as
defined in rfc1929,the server side of it.
 */
public class UserPasswordAuthenticator extends ServerAuthenticatorNone
{

    static final int METHOD_ID = 2;
    UserValidation validator;

    /**
    Construct a new UserPasswordAuthentication object, with given
    UserVlaidation scheme.

    @param v UserValidation to use for validating users.
     */
    public UserPasswordAuthenticator(UserValidation validator)
    {
        this.validator = validator;
    }

    public ServerAuthenticator startSession(Socket s) throws IOException
    {
        InputStream in = s.getInputStream();
        OutputStream out = s.getOutputStream();

        if (in.read() != 5)
        {
            return null; //Drop non version 5 messages.
        }
        if (!selectSocks5Authentication(in, out, METHOD_ID))
        {
            return null;
        }
        if (!doUserPasswordAuthentication(s, in, out))
        {
            return null;
        }

        return new ServerAuthenticatorNone(in, out);
    }

//Private Methods
//////////////////
    private boolean doUserPasswordAuthentication(Socket s, InputStream in, OutputStream out) throws IOException
    {
        int version = in.read();
        if (version != 1)
        {
            return false;
        }
        int ulen = in.read();
        if (ulen < 0)
        {
            return false;
        }
        byte[] user = new byte[ulen];
        in.read(user);
        int plen = in.read();
        if (plen < 0)
        {
            return false;
        }
        byte[] password = new byte[plen];
        in.read(password);

        if (validator.isUserValid(new String(user), new String(password), s))
        {
            //System.out.println("user valid");
            out.write(new byte[]
                {
                    1, 0
                });
        }
        else
        {
            //System.out.println("user invalid");
            out.write(new byte[]
                {
                    1, 1
                });
            return false;
        }

        return true;
    }
}
